<template>
	<view class="e-row-notice" @tap="clickHandler">
		<slot name="icon">
			<view class="e-row-notice__left-icon" v-if="icon">
				<e-icon :name="icon" :color="color" size="19"></e-icon>
			</view>
		</slot>
		<view class="e-row-notice__content" ref="e-row-notice__content"  v-if="!webviewHide">
			<view  class="e-row-notice__content__text" ref="e-row-notice__content__text" :style="[animationStyle]">
				<text v-for="(item, index) in innerText" :key="index" :style="[textStyle]">{{item}}</text>
			</view>
		</view>
		<view class="e-row-notice__right-icon" v-if="mode&&['link', 'closable'].includes(mode)">
			<e-icon v-if="mode === 'link'" name="arrow-right" :size="17" :color="color"></e-icon>
			<e-icon v-if="mode === 'closable'" @click="close" name="close" :size="16" :color="color"></e-icon>
		</view>
	</view>
</template>

<script lang="ts">
	import {defineComponent} from 'vue'
	import mpMixin from '../../../libs/mixin/mpMixin'
	export default defineComponent({
		name: "row-notice",
		mixins: [mpMixin]
	});
</script>

<script lang="ts" setup>
	import {
		ref,
		watch,
		computed,
		getCurrentInstance,
		onMounted,
		onBeforeUnmount
	} from 'vue'
	import {
		rowNoticeProps,
		rowNoticeEmits
	} from './props';
	import {
		useWebviewEvent
	} from "../../../libs/hooks";
	import {
		isString,
		sleep,
		getRect,
		getNvueRect,
	} from "../../../libs/utils";
	import {
		throwError,
		addUnit,
		getPx
	} from '../../../libs/utils/_utils'

	
	
	const ctx = getCurrentInstance()

	const props = defineProps(rowNoticeProps)
	const emit = defineEmits(rowNoticeEmits)

	const animationDuration = ref('0') // 动画执行时间
	const animationPlayState = ref('paused') // 动画的开始和结束执行
	
	const textStyle = computed(() => {
		return {
			color: props.color,
			fontSize: addUnit(props.fontSize)
		}
	})
	
	const animationStyle = computed(() => {
		return {
			animationDuration: animationDuration.value,
			animationPlayState: animationPlayState.value
		}
	})
	
	const {
		webviewHide,
		addEventListenerToWebview
	} = useWebviewEvent()
	// nvue下，内容发生变化，导致滚动宽度也变化，需要标志为是否需要重新计算宽度
	// 不能在内容变化时直接重新计算，因为nvue的animation模块上一次的滚动不是刚好结束，会有影响

	// #ifdef APP-NVUE
	let nvueInit = true
	let stopAnimation = false
	// #endif

	watch(() => props.text, (v) => {
		// #ifdef APP-NVUE
		nvueInit = true
		// #endif
		// #ifndef APP-NVUE
		vue()
		// #endif
		if (!isString(v)) {
			throwError('ENoticebar', 'e-notice-bar组件direction为row时，要求text参数为字符串形式')
		}
	})
	watch(() =>[props.fontSize, props.speed], () => {
		// #ifdef APP-NVUE
		nvueInit = true
		// #endif
		// #ifndef APP-NVUE
		vue()
		// #endif
	})

	
	// 内部对用户传入的数据进一步分割，放到多个text标签循环，否则如果用户传入的字符串很长（100个字符以上）
	// 放在一个text标签中进行滚动，在低端安卓机上，动画可能会出现抖动现象，需要分割到多个text中可解决此问题
	const innerText = computed(() => {
		let result = [],
			// 每组text标签的字符长度
			len = 20
		const textArr = (props.text||'').split('')
		for (let i = 0; i < textArr.length; i += len) {
			// 对拆分的后的text进行slice分割，得到的为数组再进行join拼接为字符串
			result.push(textArr.slice(i, i + len).join(''))
		}
		return result
	})


	const init = () => {
		// #ifdef APP-NVUE
		nvue()
		// #endif

		// #ifndef APP-NVUE
		vue()
		// #endif
	}
	// vue版处理
	const vue = async () => {
		// #ifndef APP-NVUE
		let boxWidth = 0,
			textWidth = 0
		// 进行一定的延时
		await sleep()
		// 查询盒子和文字的宽度
		textWidth = (await getRect(ctx,'.e-row-notice__content__text')).width!
		boxWidth = (await getRect(ctx,'.e-row-notice__content')).width!
		// 根据t=s/v(时间=路程/速度)，这里为何不需要加上#e-row-notice-box的宽度，因为中设置了.e-row-notice-content样式中设置了padding-left: 100%
		// 恰巧计算出来的结果中已经包含了#e-row-notice-box的宽度
		animationDuration.value = `${textWidth / Number(getPx(props.speed||'') )}s`
		// 这里必须这样开始动画，否则在APP上动画速度不会改变
		animationPlayState.value = 'paused'
		setTimeout(() => {
			animationPlayState.value = 'running'
		}, 10)
		// #endif
	}
	let animation:any
	// nvue版处理
	const nvue = async () => {
		// #ifdef APP-NVUE
		nvueInit = false
		let boxWidth = 0,
			textWidth = 0
		// 进行一定的延时
		await sleep()
		// 查询盒子和文字的宽度
		textWidth = (await getNvueRect('e-row-notice__content__text')).width!
		boxWidth = (await getNvueRect('e-row-notice__content')).width!

		// 将文字移动到盒子的右边沿，之所以需要这么做，是因为nvue不支持100%单位，否则可以通过css设置
		animation.transition(ctx?.refs.contentText, {
			styles: {
				transform: `translateX(${boxWidth}px)`
			},
		}, () => {
			// 如果非禁止动画，则开始滚动
			!stopAnimation && loopAnimation(textWidth, boxWidth)
		});
		// #endif
	}
	const loopAnimation = (textWidth: number, boxWidth: number) => {
		// #ifdef APP-NVUE
		animation.transition(ctx?.refs['e-row-notice__content__text'], {
			styles: {
				// 目标移动终点为-textWidth，也即当文字的最右边贴到盒子的左边框的位置
				transform: `translateX(-${textWidth}px)`
			},
			// 滚动时间的计算为，时间 = 路程(boxWidth + textWidth) / 速度，最后转为毫秒
			duration: (boxWidth + textWidth) / Number(getPx(props.speed||'')) * 1000,
			delay: 10
		}, () => {
			animation.transition(ctx?.refs['e-row-notice__content__text'], {
				styles: {
					// 重新将文字移动到盒子的右边沿
					transform: `translateX(${stopAnimation ? 0 : boxWidth}px)`
				},
			}, () => {
				// 如果非禁止动画，则继续下一轮滚动
				if (!stopAnimation) {
					// 判断是否需要初始化计算尺寸
					if (nvueInit) {
						nvue()
					} else {
						loopAnimation(textWidth, boxWidth)
					}
				}
			});
		})
		// #endif
	}
	// 点击通告栏
	const clickHandler = (index: number) => {
		emit('click', index)
	}
	// 点击右侧按钮，需要判断点击的是关闭图标还是箭头图标
	const close = () => {
		emit('close')
	}


	onMounted(() => {
		// #ifdef APP-PLUS
		addEventListenerToWebview()
		// #endif
		// #ifdef APP-NVUE
		 animation = uni.requireNativePlugin('animation')
		// #endif
		init()
	})

	// #ifdef APP-NVUE
	onBeforeUnmount(() => {
		stopAnimation = true
	})
	// #endif
</script>

<style lang="scss" scoped>
	@import '../../../libs/theme/rowNotice.scss';
</style>
